package cn.baddonkey.photography.agent.service.impl;

import cn.baddonkey.photography.agent.core.PageData;
import cn.baddonkey.photography.agent.entity.dto.LoginBody;
import cn.baddonkey.photography.agent.entity.dto.LoginUser;
import cn.baddonkey.photography.agent.entity.dto.UserInfoPageDto;
import cn.baddonkey.photography.agent.entity.dto.UserUpdateDto;
import cn.baddonkey.photography.agent.utils.EntityUtils;
import cn.baddonkey.photography.agent.utils.SecurityUtils;
import cn.hutool.core.util.IdUtil;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.baddonkey.photography.agent.core.enums.YesNoEnum;
import cn.baddonkey.photography.agent.entity.UserInfo;
import cn.baddonkey.photography.agent.entity.vo.UserInfoVo;
import cn.baddonkey.photography.agent.mapper.UserInfoMapper;
import cn.baddonkey.photography.agent.service.UserInfoService;
import cn.baddonkey.photography.agent.utils.PageUtils;
import com.xingyuv.captcha.model.common.ResponseModel;
import com.xingyuv.captcha.model.vo.CaptchaVO;
import com.xingyuv.captcha.service.CaptchaService;
import com.xingyuv.captcha.util.StringUtils;

import jakarta.annotation.Resource;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo>
        implements
            UserInfoService {

    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Resource
    private CaptchaService captchaService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 获取用户信息
     *
     * @return
     */
    @Override
    public UserInfoVo info() {
        String userId = SecurityUtils.getUserId();
        UserInfo userInfo = userInfoMapper.selectById(userId);
        UserInfoVo userInfoVo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, userInfoVo);
        return userInfoVo;
    }

    /**
     * 获取用户信息列表
     *
     * @param userInfoPageDto
     *            用户信息分页查询参数
     * @return PageData<UserInfoVo> 分页用户信息数据
     */
    @Override
    public PageData<UserInfoVo> list(UserInfoPageDto userInfoPageDto) {

        Page<UserInfo> page = userInfoMapper.page(
                new Page<>(userInfoPageDto.getPage(), userInfoPageDto.getLimit()),
                userInfoPageDto);
        List<UserInfoVo> list = new ArrayList<>();
        for (UserInfo record : page.getRecords()) {
            UserInfoVo userInfoVo = new UserInfoVo();
            BeanUtils.copyProperties(record, userInfoVo);
            list.add(userInfoVo);
        }
        PageData<UserInfoVo> pageData = PageUtils.getPageData(list, page.getTotal(), UserInfoVo.class);
        return pageData;
    }

    /**
     * 用户登录
     *
     * @param loginBody
     *            登录参数对象，包含用户名、密码和验证码
     * @return LoginUser 登录用户信息
     */
    @Override
    public LoginUser login(LoginBody loginBody) {
        // 滑块验证码校验
//        validateCaptchaV2(loginBody.getCaptchaVerification());
        // 用户验证
        Authentication authentication = null;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginBody.getUsername(), loginBody.getPassword()));
        } catch (Exception e) {
            log.error("登录失败，", e);
            throw new RuntimeException("用户不存在/密码错误");
        }

        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        return loginUser;
    }

    /**
     * 根据用户ID数组删除用户
     *
     * @param userIds
     *            需要删除的用户ID数组
     * @return int 删除成功的记录数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteUserByIds(String[] userIds) {
        for (String userId : userIds) {
            if (isAdmin(userId)) {
                throw new RuntimeException("不允许操作超级管理员用户");
            }
        }
        // todo 删除用户与角色关联
        // userRoleMapper.deleteUserRole(userIds);
        int result = userInfoMapper.deleteUserByIds(userIds);
        if (result > 0) {
            for (String userId : userIds) {
                // 删除token，已经登录的账号，调接口会强制退出
                Set<String> userKey = stringRedisTemplate.keys("login_tokens:" + userId + "_*");
                if (!userKey.isEmpty()) {
                    stringRedisTemplate.delete(userKey);
                }
            }
        }
    }

    /**
     * 重置用户密码
     *
     * @param dto
     *            用户更新信息对象，包含用户ID和新密码
     */
    @Override
    public void resetPwd(UserUpdateDto dto) {
        if (isAdmin(dto.getId())) {
            throw new RuntimeException("不允许操作超级管理员用户");
        }
        UserInfo userInfo = userInfoMapper.selectById(dto.getId());
        if (userInfo != null) {
            userInfo.setPassword(SecurityUtils.encryptPassword(dto.getPassword()));
            EntityUtils.setUpdateEntityInfo(userInfo);
            userInfoMapper.updateById(userInfo);
        }
    }

    /**
     * 更新用户状态
     *
     * @param dto
     *            用户更新信息对象，包含用户ID和状态
     */
    @Override
    public void updateUserStatus(UserUpdateDto dto) {
        if (isAdmin(dto.getId())) {
            throw new RuntimeException("不允许操作超级管理员用户");
        }
        UserInfo userInfo = userInfoMapper.selectById(dto.getId());
        if (userInfo != null) {
            userInfo.setStatus(dto.getStatus());
            EntityUtils.setUpdateEntityInfo(userInfo);
            userInfoMapper.updateById(userInfo);
            if (String.valueOf(YesNoEnum.YES.getCode()).equals(userInfo.getStatus())) {
                // 删除token，已经登录的账号，调接口会强制退出
                Set<String> userKey = stringRedisTemplate.keys("login_tokens:" + userInfo.getId() + "_*");
                if (!userKey.isEmpty()) {
                    stringRedisTemplate.delete(userKey);
                }
            }
        }
    }

    /**
     * 检查手机号码唯一性
     *
     * @param user
     *            用户信息对象，包含手机号码
     * @return boolean 手机号码是否唯一
     */
    @Override
    public boolean checkPhoneUnique(UserUpdateDto user) {
        String userId = StringUtils.isEmpty(user.getId()) ? "-1" : user.getId();
        UserInfo userInfo = userInfoMapper.checkPhoneUnique(user.getPhone());
        if (userInfo != null && !userId.equals(userInfo.getId())) {
            return false;
        }
        return true;
    }

    /**
     * 检查邮箱唯一性
     *
     * @param user
     *            用户信息对象，包含邮箱地址
     * @return boolean 邮箱是否唯一
     */
    @Override
    public boolean checkEmailUnique(UserUpdateDto user) {
        String userId = StringUtils.isEmpty(user.getId()) ? "-1" : user.getId();
        UserInfo userInfo = userInfoMapper.checkEmailUnique(user.getEmail());
        if (userInfo != null && !userId.equals(userInfo.getId())) {
            return false;
        }
        return true;
    }

    /**
     * 检查用户名唯一性
     *
     * @param user
     *            用户信息
     * @return 用户名是否唯一
     */
    @Override
    public boolean checkUserNameUnique(UserUpdateDto user) {
        int count = userInfoMapper.checkUserNameUnique(user.getUserName());
        return count == 0;
    }

    /**
     * 更新用户信息
     *
     * @param user
     *            用户更新信息对象
     */
    @Override
    public void updateUser(UserUpdateDto user) {
        if (isAdmin(user.getId())) {
            throw new RuntimeException("不允许操作超级管理员用户");
        }
        String userId = user.getId();
        // todo 删除用户与角色关联
        // userRoleMapper.deleteUserRoleByUserId(userId);
        // todo 新增用户与角色管理
        // insertUserRole(user);
        UserInfo userInfo = userInfoMapper.checkPhoneUnique(user.getPhone());
        userInfo.setNickName(user.getNickName());
        userInfo.setPhone(user.getPhone());
        userInfo.setEmail(user.getEmail());
        userInfo.setAvatar(user.getAvatar());
        userInfo.setStatus(user.getStatus());
        userInfo.setPhone(user.getPhone());
        userInfo.setEmail(user.getEmail());
        userInfo.setRemark(user.getRemark());
        EntityUtils.setUpdateEntityInfo(userInfo);
        int result = userInfoMapper.updateById(userInfo);

        if (result > 0 && String.valueOf(YesNoEnum.YES.getCode()).equals(userInfo.getStatus())) {
            // 删除token，已经登录的账号，调接口会强制退出
            Set<String> userKey = stringRedisTemplate.keys("login_tokens:" + user.getId() + "_*");
            if (!userKey.isEmpty()) {
                stringRedisTemplate.delete(userKey);
            }
        }
    }

    @Override
    public int insertUser(UserUpdateDto user) {
        UserInfo userInfo = new UserInfo();
        BeanUtils.copyProperties(user, userInfo);
        userInfo.setId(IdUtil.simpleUUID());
        userInfo.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        userInfo.setDeleted(false);
        EntityUtils.setInsertEntityInfo(userInfo);
        int row = userInfoMapper.insert(userInfo);

        // todo 新增用户与角色管理
        // insertUserRole(user);

        return row;
    }

    /**
     * 判断是否为管理员用户
     *
     * @param userId
     *            用户ID
     * @return boolean 是否为管理员
     */
    private boolean isAdmin(String userId) {
        return "1".equals(userId);
    }

    /**
     * 验证滑块验证码
     *
     * @param captchaVerification
     *            验证码验证信息
     */
    private void validateCaptchaV2(String captchaVerification) {
        // 校验验证码
        CaptchaVO captchaVO = new CaptchaVO();
        captchaVO.setCaptchaVerification(captchaVerification);
        ResponseModel response = captchaService.verification(captchaVO);
        // 验证不通过
        if (!response.isSuccess()) {
            throw new RuntimeException("验证码校验不通过");
        }
    }
}
